﻿using System;
using System.ComponentModel.Composition;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using DocumentFormat.OpenXml.Packaging;

namespace Songhay.OpenXml.Transformations
{
    using Songhay.OpenXml.Models;

    /// <summary>
    /// Transforms selected Open XML WordML image elements.
    /// </summary>
    [Export(typeof(IWordProcessingDocumentTransformation))]
    public class ImageTransformation : IWordProcessingDocumentTransformation
    {
        #region IWordProcessingDocumentTransformation Members

        /// <summary>
        /// Gets or sets the execution ordinal.
        /// </summary>
        /// <value>The execution ordinal.</value>
        public byte ExecutionOrdinal { get; set; }

        /// <summary>
        /// Determines whether this instance can transform the specified word doc.
        /// </summary>
        /// <param name="wordDoc">The Word document.</param>
        /// <param name="settings">The settings.</param>
        /// <param name="node">The node.</param>
        /// <returns>
        /// 	<c>true</c> if this instance can transform the specified word doc; otherwise, <c>false</c>.
        /// </returns>
        public bool CanTransform(WordprocessingDocument wordDoc,
            SonghayHtmlConverterSettings settings, XNode node)
        {
            return this.HasElementName(node, SonghayW.drawing) ||
                this.HasElementName(node, SonghayW.pict);
        }

        /// <summary>
        /// Transforms the specified Word document.
        /// </summary>
        /// <param name="wordDoc">The Word document.</param>
        /// <param name="settings">The settings.</param>
        /// <param name="node">The node.</param>
        /// <param name="imageHandler">The image handler.</param>
        public object Transform(WordprocessingDocument wordDoc,
            SonghayHtmlConverterSettings settings, XNode node,
            Func<ImageInfo, XElement> imageHandler)
        {
            var element = node as XElement;

            if(element.Name == SonghayW.drawing)
            {
                if(imageHandler == null) return null;

                XElement containerElement = element.Elements()
                    .Where(e => e.Name == SonghayWP.inline || e.Name == SonghayWP.anchor)
                    .FirstOrDefault();
                if(containerElement != null)
                {
                    int? extentCx = (int?)containerElement.Elements(SonghayWP.extent)
                        .Attributes(SonghayWP.cx).FirstOrDefault();
                    int? extentCy = (int?)containerElement.Elements(SonghayWP.extent)
                        .Attributes(SonghayWP.cy).FirstOrDefault();
                    string altText = (string)containerElement.Elements(SonghayWP.docPr)
                        .Attributes(SonghayWP.descr).FirstOrDefault();
                    if(altText == null)
                        altText = (string)containerElement.Elements(SonghayWP.docPr)
                            .Attributes(SonghayWP.name).FirstOrDefault();
                    if(altText == null)
                        altText = "";

                    XElement blipFill = containerElement.Elements(SonghayA.graphic)
                        .Elements(SonghayA.graphicData)
                        .Elements(SonghayPic.pic).Elements(SonghayPic.blipFill).FirstOrDefault();
                    if(blipFill != null)
                    {
                        string imageRid = (string)blipFill.Elements(SonghayA.blip).Attributes(SonghayR.embed)
                            .FirstOrDefault();
                        ImagePart imagePart = (ImagePart)wordDoc.MainDocumentPart
                            .GetPartById(imageRid);
                        string contentType = imagePart.ContentType;
                        if(contentType == "image/png" ||
                            contentType == "image/gif" ||
                            contentType == "image/tiff" ||
                            contentType == "image/jpeg")
                        {
                            using(Stream partStream = imagePart.GetStream())
                            using(Bitmap bitmap = new Bitmap(partStream))
                            {
                                if(extentCx != null && extentCy != null)
                                {
                                    ImageInfo imageInfo = new ImageInfo()
                                    {
                                        Bitmap = bitmap,
                                        ImgStyleAttribute = new XAttribute(SonghayXhtml.style,
                                            string.Format("width: {0}in; height: {1}in",
                                                (float)extentCx / (float)ImageInfo.EmusPerInch,
                                                (float)extentCy / (float)ImageInfo.EmusPerInch)),
                                        ContentType = contentType,
                                        DrawingElement = element,
                                        AltText = altText,
                                    };
                                    return imageHandler(imageInfo);
                                }
                                ImageInfo imageInfo2 = new ImageInfo()
                                {
                                    Bitmap = bitmap,
                                    ContentType = contentType,
                                    DrawingElement = element,
                                    AltText = altText,
                                };
                                return imageHandler(imageInfo2);
                            };
                        }
                    }
                }
            }

            if(element.Name == SonghayW.pict)
            {
                if(imageHandler == null) return null;

                string imageRid = (string)element.Elements(SonghayVML.shape)
                    .Elements(SonghayVML.imagedata).Attributes(SonghayR.id).FirstOrDefault();
                string style = (string)element.Elements(SonghayVML.shape)
                    .Attributes(SonghayXhtml.style).FirstOrDefault();
                if(imageRid != null)
                {
                    try
                    {
                        ImagePart imagePart = (ImagePart)wordDoc.MainDocumentPart
                            .GetPartById(imageRid);
                        string contentType = imagePart.ContentType;
                        if(contentType == "image/png" ||
                            contentType == "image/gif" ||
                            contentType == "image/tiff" ||
                            contentType == "image/jpeg")
                        {
                            //string style = element.
                            using(Stream partStream = imagePart.GetStream())
                            using(Bitmap bitmap = new Bitmap(partStream))
                            {
                                ImageInfo imageInfo = new ImageInfo()
                                {
                                    Bitmap = bitmap,
                                    ContentType = contentType,
                                    DrawingElement = element,
                                };
                                if(style != null)
                                {
                                    float? widthInPoints = null;
                                    float? heightInPoints = null;
                                    string[] tokens = style.Split(';');
                                    var widthString = tokens
                                        .Select(t => new
                                        {
                                            Name = t.Split(':').First(),
                                            Value = t.Split(':').Skip(1)
                                                .Take(1).FirstOrDefault(),
                                        })
                                        .Where(p => p.Name == "width")
                                        .Select(p => p.Value)
                                        .FirstOrDefault();
                                    if(widthString != null &&
                                        widthString.Substring(widthString.Length - 2) == "pt")
                                    {
                                        float w;
                                        if(float.TryParse(widthString.Substring(0,
                                            widthString.Length - 2), out w))
                                            widthInPoints = w;
                                    }
                                    var heightString = tokens
                                        .Select(t => new
                                        {
                                            Name = t.Split(':').First(),
                                            Value = t.Split(':').Skip(1).Take(1).FirstOrDefault(),
                                        })
                                        .Where(p => p.Name == "height")
                                        .Select(p => p.Value)
                                        .FirstOrDefault();
                                    if(heightString != null &&
                                        heightString.Substring(heightString.Length - 2) == "pt")
                                    {
                                        float h;
                                        if(float.TryParse(heightString.Substring(0,
                                            heightString.Length - 2), out h))
                                            heightInPoints = h;
                                    }
                                    if(widthInPoints != null && heightInPoints != null)
                                        imageInfo.ImgStyleAttribute = new XAttribute(
                                            SonghayXhtml.style, string.Format(
                                                "width: {0}pt; height: {1}pt",
                                                widthInPoints, heightInPoints));
                                }
                                return imageHandler(imageInfo);
                            };
                        }
                    }
                    catch(ArgumentOutOfRangeException)
                    {
                        return null;
                    }
                }
            }

            return null;
        }

        #endregion
    }
}
